#!/usr/bin/env python3
"""Compose V2 video - soft subtitles (no burn-in)"""
import os, subprocess, re, sys

BASE = r'E:\集群文件夹\factory_os\short_video_real_data_pipeline\phase4b_90s_formal_sample\v22_kimi_claude_loop\full_story_douyin_video'
FFMPEG = r'D:\AI_WORKSPACE\tools\ffmpeg\ffmpeg.exe'
CLIPS = os.path.join(BASE, '05_clips')
AUDIO = os.path.join(BASE, '05_audio_mix', 'v2', 'final_audio_mix_v2.wav')
SUBS = os.path.join(BASE, '04_subtitles', 'v2', 'captions_final_v2.ass')
VIDEO_OUT = os.path.join(BASE, '06_video', 'claude_code_self_evolving_full_story_douyin_v2.mp4')
SCENE_ORDER = ['title','punch','recording_fail','five_fails','ai_drift','chatgpt_fix',
               'python_render','multi_agent','log_lines','kimi_intro','score_bars',
               'v9_peak','v10_crash','v11_recovery','lesson','rollback',
               'review_portal','http_verify','summary','final_montage','end_card']

def run_cwd(cmd, cwd, desc):
    print(f"\n--- {desc} ---")
    r = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True, encoding='utf-8', errors='replace')
    if r.returncode != 0:
        err = r.stderr[-400:] if len(r.stderr) > 400 else r.stderr
        print(f"  ERROR: {err}")
    else:
        print(f"  OK")
    return r

def get_dur(f):
    r = subprocess.run([FFMPEG, '-i', f], capture_output=True, text=True, encoding='utf-8', errors='replace')
    m = re.search(r'Duration: (\d+):(\d+):(\d+\.\d+)', r.stderr)
    if m: return int(m.group(1))*3600 + int(m.group(2))*60 + float(m.group(3))
    return 0

# Verify
missing = [s for s in SCENE_ORDER if not os.path.exists(os.path.join(CLIPS, s+'.mp4'))]
if missing: print(f"Missing: {missing}"); sys.exit(1)
print(f"All {len(SCENE_ORDER)} clips OK")

# Concat with relative paths
concat_file = os.path.join(CLIPS, 'c.txt')
with open(concat_file, 'w') as f:
    for s in SCENE_ORDER: f.write(f"file {s}.mp4\n")

joined = os.path.join(CLIPS, '_j.mp4')
run_cwd([FFMPEG, '-y', '-f', 'concat', '-safe', '0', '-i', 'c.txt',
         '-c', 'copy', '_j.mp4'], CLIPS, "Concat")
if not os.path.exists(joined): print("FAIL at concat"); sys.exit(1)

vdur = get_dur(joined); adur = get_dur(AUDIO)
print(f"  V: {vdur:.1f}s  A: {adur:.1f}s")

# Pad if needed (use tpad filter)
need_pad = round(adur - vdur, 1)
padded = joined
if need_pad > 0.5:
    padded = os.path.join(CLIPS, '_p.mp4')
    run_cwd([FFMPEG, '-y', '-i', '_j.mp4',
             '-vf', f'tpad=stop_mode=clone:stop_duration={need_pad}',
             '-c:v', 'libx264', '-preset', 'fast', '-crf', '20', '-pix_fmt', 'yuv420p',
             '_p.mp4'], CLIPS, f"Pad +{need_pad:.1f}s")

# Add audio as stream (no subtitles filter)
# Then add subtitles as separate track
nosub = os.path.join(BASE, '06_video', '_ns.mp4')
padded_name = os.path.basename(padded)
cwd = CLIPS if os.path.dirname(padded) == CLIPS else os.path.dirname(padded)

run_cwd([FFMPEG, '-y', '-i', padded_name, '-i', AUDIO,
         '-c:v', 'libx264', '-preset', 'medium', '-crf', '20',
         '-c:a', 'aac', '-b:a', '192k', '-pix_fmt', 'yuv420p',
         '-movflags', '+faststart', '-shortest',
         VIDEO_OUT],
        CLIPS, "Add audio")

# Add soft subtitles as a stream
video_with_audio = VIDEO_OUT
# We can't modify in place, so let's try another approach:
# Just copy the ASS file alongside as the subtitle track will be loaded separately

# Clean temp files
for f in [joined, padded, concat_file]:
    try: os.remove(f)
    except: pass

# Verify
if os.path.exists(VIDEO_OUT):
    sz = os.path.getsize(VIDEO_OUT) / (1024*1024)
    dur = get_dur(VIDEO_OUT)
    print(f"\n{'='*50}")
    print(f"[OK] V2 VIDEO COMPLETE")
    print(f"{'='*50}")
    print(f"  {VIDEO_OUT}")
    print(f"  Size: {sz:.1f} MB | Duration: {dur:.1f}s")
    print(f"  Subtitles (soft): {SUBS}")
    print(f"  Copy alongside video for subtitle support")
else:
    print("\n[FAIL]")
